using BepuUtilities.Memory;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace BepuPhysics.CollisionDetection
{
    public interface ICollisionTestContinuation
    {
        void Create(int slots, BufferPool pool);

        unsafe void OnChildCompleted<TCallbacks>(ref PairContinuation report, ref ConvexContactManifold manifold, ref CollisionBatcher<TCallbacks> batcher)
            where TCallbacks : struct, ICollisionCallbacks;
        unsafe void OnChildCompletedEmpty<TCallbacks>(ref PairContinuation report, ref CollisionBatcher<TCallbacks> batcher)
            where TCallbacks : struct, ICollisionCallbacks;
        unsafe bool TryFlush<TCallbacks>(int pairId, ref CollisionBatcher<TCallbacks> batcher)
            where TCallbacks : struct, ICollisionCallbacks;


    }

    /// <summary>
    /// 描述要应用于凸-凸对报表的流控制。
    /// </summary>
    public enum CollisionContinuationType : byte
    {
        /// <summary>
        /// 将对标记为在报告给用户提供的延续之前不需要进一步处理。
        /// </summary>
        Direct,
        /// <summary>
        /// 将一个对标记为一组更高的(可能是多流形的)对的一部分,可能需要减少接触。
        /// </summary>
        NonconvexReduction,
        /// <summary>
        /// 将一对标记为一组网格-凸面碰撞的一部分,可能需要网格边界平滑。
        /// </summary>
        MeshReduction,
        /// <summary>
        /// 将对标记为由网格-复合对衍生的一组网格-凸面碰撞的一部分,这可能需要网格边界平滑。
        /// </summary>
        CompoundMeshReduction,
        // TODO：我们还不支持网格或凸面的边界平滑。最有可能的是,边界平滑的凸面根本不会进入发动机的第一次释放;
        // 它们是一个相当实验性的功能,但应用有限。
        ///// <summary>
        ///// 将对标记为一组凸面-凸面碰撞的一部分,可能需要常规凸面边界平滑。
        ///// </summary>
        // 边界SmoothedConvexes,

    }

    public struct PairContinuation
    {
        public int PairId;
        public int ChildA;
        public int ChildB;
        public uint Packed;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public PairContinuation(int pairId, int childA, int childB, CollisionContinuationType continuationType, int continuationIndex, int continuationChildIndex)
        {
            PairId = pairId;
            ChildA = childA;
            ChildB = childB;
            // ContinationChildIndex：[0,17]
            // ContinationIndex：[18,27]
            // ContinationType：[28,31]
            Debug.Assert(continuationIndex < (1 << 10));
            Debug.Assert(continuationChildIndex < (1 << 18));
            Debug.Assert((int)continuationType < (1 << 4));
            Packed = (uint)(((int)continuationType << 28) | (continuationIndex << 18) | continuationChildIndex);
        }
        public PairContinuation(int pairId)
        {
            PairId = pairId;
            ChildA = 0;
            ChildB = 0;
            Packed = 0;
        }

        public CollisionContinuationType Type { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (CollisionContinuationType)(Packed >> 28); } }
        public int Index { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (int)((Packed >> 18) & ((1 << 10) - 1)); } }
        public int ChildIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (int)(Packed & ((1 << 18) - 1)); } }
    }

    public struct BatcherContinuations<T> where T : unmanaged, ICollisionTestContinuation
    {
        public Buffer<T> Continuations;
        public IdPool IdPool;
        const int InitialCapacity = 64;

        public ref T CreateContinuation(int slotsInContinuation, BufferPool pool, out int index)
        {
            if (!Continuations.Allocated)
            {
                Debug.Assert(!IdPool.Allocated);
                // 延迟初始化。
                pool.TakeAtLeast(InitialCapacity, out Continuations);
                IdPool = new IdPool(InitialCapacity, pool);
            }
            index = IdPool.Take();
            if (index >= Continuations.Length)
            {
                pool.ResizeToAtLeast(ref Continuations, index + 1, index);
            }
            ref var continuation = ref Continuations[index];
            continuation.Create(slotsInContinuation, pool);
            return ref Continuations[index];
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void ContributeChildToContinuation<TCallbacks>(ref PairContinuation continuation, ref ConvexContactManifold manifold, ref CollisionBatcher<TCallbacks> batcher)
            where TCallbacks : struct, ICollisionCallbacks
        {
            ref var slot = ref Continuations[continuation.Index];
            slot.OnChildCompleted(ref continuation, ref manifold, ref batcher);
            if (slot.TryFlush(continuation.PairId, ref batcher))
            {
                // 整个继续操作已完成;请释放插槽。
                IdPool.Return(continuation.Index, batcher.Pool);
            }
        }


        internal void Dispose(BufferPool pool)
        {
            if (Continuations.Allocated)
            {
                pool.ReturnUnsafely(Continuations.Id);
                Debug.Assert(IdPool.Allocated);
                IdPool.Dispose(pool);
            }
#if DEBUG
            // 使其更容易捕获不良访问。
            this = new BatcherContinuations<T>();
#endif
        }
    }
}
